/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/
package org.activequant.core.domainmodel;

import static org.activequant.util.tools.IdentityUtils.safeCompare;
import static org.activequant.util.tools.IdentityUtils.safeHashCode;

import java.io.Serializable;

import org.activequant.core.types.Currency;
import org.activequant.core.types.Expiry;
import org.activequant.core.types.SecurityType;
import org.activequant.core.types.TimeFrame;
import org.activequant.core.types.TimeStamp;
import org.activequant.util.tools.IdentityUtils;


/**
 * Specifies a sublist of market-data entities for a given instrument specification.
 * E.g. a candle series is defined by it's resolution (timeframe), start (timestamp)
 * end (timestamp)  and instrument (specification).
 * <br>
 * Holds the following associated variables:
 * <ul>
 * <li>instrumentSpecification(InstrumentSpecification)</li>
 * <li>startTimeStamp(TimeStamp)</li>
 * <li>endTimeStamp(TimeStamp)</li>
 * <li>timeFrame(TimeFrame)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [03.05.2006] Created (Ulrich Staudinger)<br>
 *  - [03.05.2007] Cleanup (Erik Nijkamp)<br>
 *  - [19.06.2007] added InstrumentSpecification (Ulrich Staudinger)<br>
 *  - [20.06.2007] Simplified (Erik Nijkamp)<br>
 *  - [27.10.2007] Added object identity code (Erik Nijkamp)<br>
 *  
 *
 *  @author Ulrich Staudinger
 *  @author Erik Nijkamp
 */
public class SeriesSpecification implements Comparable<SeriesSpecification>, Serializable {

	private static final long serialVersionUID = -2190464710376768025L;
	/**
	 * private InstrumentSpecification instrumentSpecification;
	 */
	private InstrumentSpecification instrumentSpecification;
	/**
	 * private TimeStamp startTimeStamp;
	 */
	private TimeStamp startTimeStamp;
	/**
	 * private TimeStamp endTimeStamp;
	 */
	private TimeStamp endTimeStamp;
	/**
	 * private TimeFrame timeFrame;
	 */
	private TimeFrame timeFrame;
	/**
	 * empty constructor
	 */
	public SeriesSpecification() {

	}
	/**
	 * Constructs a SeriesSpecification using the given symbol(Symbol) to construct an InstrumentSpecification and then sets its associated instrumentSpecification(InstrumentSpecification) with it.
	 * @param symbol
	 */
	public SeriesSpecification(Symbol symbol) {
		this.instrumentSpecification = new InstrumentSpecification(symbol);
	}
	/**
	 * Constructs a SeriesSpecification using the given symbol(Symbol) to construct an InstrumentSpecification and then sets its associated instrumentSpecification(InstrumentSpecification) with it.<br/>
	 * Sets its associated timeFrame(TimeFrame) with the given timeFrame(TimeFrame).
	 * @param symbol
	 * @param timeFrame
	 */
	public SeriesSpecification(Symbol symbol, TimeFrame timeFrame) {
		this.instrumentSpecification = new InstrumentSpecification(symbol);
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given spec(InstrumentSpecification) and timeFrame(TimeFrame) to set its associated instrumentSpecification(InstrumentSpecification) and timeFrame(TimeFrame)
	 * @param spec
	 * @param timeFrame
	 */
	public SeriesSpecification(InstrumentSpecification spec, TimeFrame timeFrame) {
		this.instrumentSpecification = spec;
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given symbol(Symbol) to construct an InstrumentSpecification and then sets its associated instrumentSpecification(InstrumentSpecification) with it.<br/>
	 * Sets its associated startTimeStamp(TimeStamp) with the given startDate(TimeStamp).<br/>
	 * Sets its associated endTimeStamp(TimeStamp) with the given endDate(TimeStamp).<br/>
	 * Sets its associated timeFrame(TimeFrame) with the given timeFrame(TimeFrame).
	 * @param symbol
	 * @param startDate
	 * @param endDate
	 * @param timeFrame
	 */
	public SeriesSpecification(Symbol symbol, TimeStamp startDate, TimeStamp endDate, TimeFrame timeFrame) {
		this.instrumentSpecification = new InstrumentSpecification(symbol);
		this.startTimeStamp = startDate;
		this.endTimeStamp = endDate;
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given spec(InstrumentSpecification) to set its associated instrumentSpecification(InstrumentSpecification).<br/>
	 * Sets its associated startTimeStamp(TimeStamp) with the given startDate(TimeStamp).<br/>
	 * Sets its associated endTimeStamp(TimeStamp) with the given endDate(TimeStamp).<br/>
	 * Sets its associated timeFrame(TimeFrame) with the given timeFrame(TimeFrame).
	 * @param spec
	 * @param startDate
	 * @param endDate
	 * @param timeFrame
	 */
	public SeriesSpecification(InstrumentSpecification spec, TimeStamp startDate,TimeStamp endDate, TimeFrame timeFrame) {
		this.instrumentSpecification = spec;
		this.startTimeStamp = startDate;
		this.endTimeStamp = endDate;
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given spec(InstrumentSpecification) to set its associated instrumentSpecification(InstrumentSpecification).
	 * @param spec
	 */
	public SeriesSpecification(InstrumentSpecification spec) {
		this.instrumentSpecification = spec;
	}

	/**
	 * Constructs a copy SeriesSpecification of the given spec(SeriesSpecification)
	 * Copy constructor.
	 * @param spec
	 */
	public SeriesSpecification(SeriesSpecification spec) {
		this.instrumentSpecification = new InstrumentSpecification(spec.getInstrumentSpecification());
		this.timeFrame = spec.timeFrame;
		this.startTimeStamp = spec.getStartTimeStamp();
		this.endTimeStamp = spec.getEndTimeStamp();
	}
	/**
	 * Constructs a SeriesSpecification using the given timeFrame(TimeFrame) and spec(InstrumentSpecification) to set its associated 
	 * timeFrame(TimeFrame) and instrumentSpecification(InstrumentSpecification).
	 * @param timeFrame
	 * @param spec
	 */
	public SeriesSpecification(TimeFrame timeFrame, InstrumentSpecification spec) {
		this(spec);
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given timeFrame(TimeFrame) to set its associated timeFrame(TimeFrame).<br/>
	 * Then, it constructs an InstrumentSpecification with the given symbol(Symbol), exchange(String), vendor(String), currency(Currency) and securityType(SecurityType) and then sets its associated instrumentSpecification(InstrumentSpecification) with it.
	 * @param timeFrame
	 * @param symbol
	 * @param exchange
	 * @param vendor
	 * @param currency
	 * @param securityType
	 */
	public SeriesSpecification(TimeFrame timeFrame, Symbol symbol, String exchange, String vendor, Currency currency, SecurityType securityType) {
		this.instrumentSpecification = new InstrumentSpecification(symbol, exchange, vendor, currency, securityType);
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given timeFrame(TimeFrame) to set its associated timeFrame(TimeFrame).<br/>
	 * Then, it constructs an InstrumentSpecification with the given symbol(Symbol), exchange(String), vendor(String), currency(Currency), securityType(SecurityType) and expiry(Expiry) and then sets its associated instrumentSpecification(InstrumentSpecification) with it.
	 * @param timeFrame
	 * @param symbol
	 * @param exchange
	 * @param vendor
	 * @param currency
	 * @param securityType
	 * @param expiry
	 */
	public SeriesSpecification(TimeFrame timeFrame, Symbol symbol, String exchange, String vendor, Currency currency, SecurityType securityType, Expiry expiry) {
		this.instrumentSpecification = new InstrumentSpecification(symbol, exchange, vendor, currency, securityType, expiry);
		this.timeFrame = timeFrame;
	}
	/**
	 * Constructs a SeriesSpecification using the given symbol(Symbol) to construct an InstrumentSpecification and then sets its associated instrumentSpecification(InstrumentSpecification) with it.<br/>
	 * Sets its associated timeFrame(TimeFrame) with the given timeFrame(TimeFrame).
	 * @param timeFrame
	 * @param symbol
	 */
	public SeriesSpecification(TimeFrame timeFrame, Symbol symbol) {
		this.instrumentSpecification = new InstrumentSpecification(symbol);
		this.timeFrame = timeFrame;
	}
	/**
	 * returns the associated endTimeStamp(TimeStamp)
	 * @return
	 */
	public TimeStamp getEndTimeStamp() {
		return endTimeStamp;
	}
	/**
	 * sets the associated endTimeStamp(TimeStamp) with the given end(TimeStamp)
	 * @param end
	 */
	public void setEndTimeStamp(TimeStamp end) {
		this.endTimeStamp = end;
	}
	/**
	 * returns the associated startTimeStamp(TimeStamp)
	 * @return
	 */
	public TimeStamp getStartTimeStamp() {
		return startTimeStamp;
	}
	/**
	 * sets the associated startTimeStamp(TimeStamp) with the given start(TimeStamp)
	 * @param start
	 */
	public void setStartTimeStamp(TimeStamp start) {
		this.startTimeStamp = start;
	}
	/**
	 * returns the associated timeFrame(TimeFrame)
	 * @return
	 */
	public TimeFrame getTimeFrame() {
		return timeFrame;
	}
	/**
	 * sets the associated timeFrame(TimeFrame) with the given timeFrame(TimeFrame)
	 * @param timeFrame
	 */
	public void setTimeFrame(TimeFrame timeFrame) {
		this.timeFrame = timeFrame;
	}
	/**
	 * Returns a string in the form "${id}\t${symbol}\t${exchange}\t${vendor}\t${currency}\t${securityType}\t${expiry}\t${contractRight}\t${strike} \t ${startTimeStamp} \t ${endTimeStamp}"
	 */
	public String toString() {
		return instrumentSpecification.toString() + " \t " + startTimeStamp + " \t " + endTimeStamp;
	}
	/**
	 * returns the associated instrumentSpecification(InstrumentSpecification)
	 * @return
	 */
	public InstrumentSpecification getInstrumentSpecification() {
		return instrumentSpecification;
	}
	/**
	 * sets the associated instrumentSpecification(InstrumentSpecification) with the given instrumentSpecification(InstrumentSpecification)
	 * @param instrumentSpecification
	 */
	public void setInstrumentSpecification(InstrumentSpecification instrumentSpecification) {
		this.instrumentSpecification = instrumentSpecification;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public int hashCode() {
		// ATTENTION: keep in sync with compareTo()
		return safeHashCode(this.instrumentSpecification) 
			+ safeHashCode(this.startTimeStamp)
			+ safeHashCode(this.endTimeStamp)
			+ safeHashCode(this.timeFrame);
	}

	/**
	 * {@inheritDoc}
	 */
	public int compareTo(SeriesSpecification other) {
		// ATTENTION: keep in sync with hashCode();
		int rc;
		
		rc = safeCompare(this.instrumentSpecification, other.instrumentSpecification);
		if(rc != 0) return rc;
		rc = safeCompare(this.startTimeStamp, other.startTimeStamp);
		if(rc != 0) return rc;
		rc = safeCompare(this.endTimeStamp, other.endTimeStamp);
		if(rc != 0) return rc;
		rc = safeCompare(this.timeFrame, other.timeFrame);
		
		return rc;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean equals(Object other) {
		// NOTE: delegates to compareTo()
		return IdentityUtils.equalsTo(this, other);
	}

}